<!-- 表单 -->
<template>
  <DraggableModal :width="width" :open="open" @cancel="onCancel" :maskClosable="false" :footer="null" :title="title">
    <div class="modal-content">
      <a-spin :spinning="isLoading">
        <a-form ref="formRef" :model="formData" :rules="rules" :labelCol="labelCol" labelWrap :wrapperCol="wrapperCol">
          <!-- 动态渲染父组件传递的 formConfig，用 title 作为标签文字 -->
          <FormItemTemplate :formConfig="formConfig" :formData="formData" :validateInfos="validateInfos" />
        </a-form>
      </a-spin>
    </div>

    <!-- 表单按钮 -->
    <div class="modal-footer">
      <a-form-item class="form-item-buttons">
        <a-flex justify="center" :gap="16">
          <a-button type="primary" htmlType="submit" @click="onFinish">确定</a-button>
          <a-button @click="onCancel">取消</a-button>
        </a-flex>
      </a-form-item>
    </div>
  </DraggableModal>
</template>
<script setup lang="ts">
  import { ref, reactive, computed, useTemplateRef } from 'vue';
  import { FormUtil, Rules } from '@/utils/utils';
  import { message, type FormInstance } from 'ant-design-vue';
  import { bizApi } from '@/api/biz';
  import { isFunction } from 'lodash-es';
  import DraggableModal from '@/components/common/modal/draggable-modal.vue';
  import FormItemTemplate, {
    type FormItemTemplateConfig,
    type FormItemTemplateProps,
  } from '@/components/template/form-item/form-item-template.vue';
  import type { Rule } from 'ant-design-vue/es/form';

  // ========================== 1. 类型定义 ==========================
  /** 表单项配置类型 */
  export interface ModalFormItemConfig extends FormItemTemplateConfig {
    defaultValue?: any; // 字段默认值
    required?: boolean; // 是否必填（用于生成校验规则）
  }

  export interface ModalFormTemplateProps {
    title: string; // 弹窗标题
    open?: boolean; // 弹窗是否打开
    formConfig: ModalFormItemConfig[]; // 父组件传递的配置
    width?: number; // 弹窗宽度
    labelWidth?: number | string; // 标签宽度（默认120px）
    getHiddenParams?: boolean; // 是否获取隐藏字段的值
  }

  /** 组件接收的 Props */
  const props = defineProps<ModalFormTemplateProps>();

  /** 表单布局 */
  const labelCol = { style: { width: props.labelWidth ?? '120px' } };
  const wrapperCol = { span: 24 };

  // ========================== 2. 核心工具函数：根据 title + 组件类型 自动生成 placeholder ==========================
  const formInstance = useTemplateRef<FormInstance>('formRef');
  const isLoading = ref(false);
  // 提交报错时，从报错信息中提取出来，回显表单报错信息
  const validateInfos = ref<FormItemTemplateProps['validateInfos']>({});

  // 表单数据：根据配置初始化（含默认值）
  const formData = reactive<Record<string, any>>({
    ...props.formConfig.reduce(
      (initData, item) => {
        initData[item.dataIndex] = item.defaultValue ?? undefined;
        return initData;
      },
      {} as Record<string, any>
    ),
  });

  // 表单校验规则：根据 title 生成提示
  const rules = computed(() => {
    return props.formConfig.reduce((ruleObj: Record<string, Rule[]>, item) => {
      const { required, title, dataIndex, uploadMaxSize, type } = item;
      if (!ruleObj[dataIndex]) {
        ruleObj[dataIndex] = [];
      }
      // 通用必填校验规则
      if (required && type !== 'upload') {
        const message = Rules.getRequiredRuleMessage(item);
        ruleObj[dataIndex] = ruleObj[dataIndex].concat(Rules.getRequiredRules(message));
      }
      // 文件上传必填校验规则
      if (required && type === 'upload') {
        const message = Rules.getRequiredRuleMessage(item);
        ruleObj[dataIndex] = ruleObj[dataIndex].concat(Rules.getRequiredUploadRules(message));
      }
      // 上传文件大小限制
      if (type === 'upload') {
        // 文件大小限制默认 5 MB
        const max = uploadMaxSize ?? 5;
        ruleObj[dataIndex] = ruleObj[dataIndex].concat(Rules.getUploadFileMaxSizeRules(title, max));
      }
      return ruleObj;
    }, {});
  });
  /**
   * 遍历动态表单项，生成 { dataIndex: 值 } 格式的字面量参数
   * @param filterEmpty 是否过滤空值（undefined/''/null），默认 true
   * @returns 字面量参数对象
   */
  const getFormParams = (filterEmpty: boolean = true) => {
    // 1. 遍历 formConfig，获取所有有效表单项（排除 hidden 隐藏项）
    const validItems = props.formConfig.filter((item) => {
      // 获取所有表单字段，包括隐藏值（根据需求开关）
      if (props.getHiddenParams) {
        return true;
      }
      // 获取表单字段不包含隐藏值
      return isFunction(item.hidden) ? !item.hidden(formData) : !item.hidden;
    });

    // 2. 遍历有效项，匹配 formData 的值，组成字面量对象
    const formParams = validItems.reduce(
      (params, item) => {
        const key = item.dataIndex; // 字段名（dataIndex）
        const value = formData[key]; // 字段值（formData 中对应的值）

        // 3. 可选过滤无效数据（根据需求开关）
        if (filterEmpty) {
          // 过滤规则：排除 undefined、''、null（可根据业务调整）
          const isEmpty = value === undefined || value === '' || value === null;
          if (!isEmpty) {
            params[key] = value;
          }
        } else {
          // 不过滤，保留所有字段（包括空值）
          params[key] = value;
        }

        return params;
      },
      {} as Record<string, any>
    ); // 最终返回的字面量对象

    // 3. 遍历upload数据，进行特殊处理
    const dataIndexList = props.formConfig.filter((item) => item.type === 'upload').map((item) => item.dataIndex);
    for (const dataIndex of dataIndexList) {
      const value = formData[dataIndex];
      if (Array.isArray(value)) {
        // 将文件对象数组转换为 fileKey 字符串数组
        formParams[dataIndex] = value.map((v: any) => v?.response?.biz_content?.fileKey);
      }
    }
    return formParams;
  };

  /** 组件发出 关闭、保存  事件 */
  const emits = defineEmits<{
    cancel: [val: boolean]; //通知调用组件(父组件) 执行 父组件 的 @cancel 的方法
    finish: []; //通知调用组件(父组件) 执行 父组件 的 @finish 的方法
  }>();

  /* 弹窗 关闭 事件，仅通知调用组件(父组件) */
  const onCancel = () => {
    emits('cancel', false);
  };

  /* 弹窗 保存 事件，仅通知调用组件 */
  const onFinish = () => {
    emits('finish');
  };

  const postAction = ref('');
  const postParams = ref({});

  /* 数据服务请求（访问服务端接口获取数据） */
  async function postFormData(action: string, params: Record<string, any>): Promise<boolean> {
    isLoading.value = true;
    let flag: boolean | Promise<any> = false;
    try {
      await formInstance.value?.validate();
    } catch (error) {
      isLoading.value = false;
      return flag;
    }
    try {
      postParams.value = params; //赋值给响应变量
      postAction.value = action; //赋值给响应变量
      const result = await bizApi.httpSave(postAction.value, postParams.value);
      message.success({
        content: result.sub_message || '数据保存成功',
      });
      flag = true;
    } catch (error: any) {
      const validateInfo = FormUtil.getValidateInfoByApiError(error.message);
      // 没有错误信息的情况下直接抛出错误，避免业务逻辑上产生误解
      if (!validateInfo) {
        throw new Error(`接口抛出的错误message格式不正确，无法提取错误信息回填至表单${error.message}`);
      }
      validateInfos.value = validateInfo;
      flag = Promise.reject(error);
    }
    isLoading.value = false;
    return flag;
  }

  /* 数据服务请求（访问服务端接口获取数据） */
  async function getDataInfo(action: string, params: Record<string, any>) {
    isLoading.value = true;
    try {
      const result = await bizApi.httpList(action, params);
      //console.log("result",result)
      Object.assign(formData, result);
      isLoading.value = false;
    } catch (error: any) {}
    isLoading.value = false;
    return false;
  }
  /* 重置表单 */
  const resetForm = () => {
    formInstance.value?.resetFields();
    validateInfos.value = {};
  };

  /* ----------------------- 暴露方法给父组件 ------------------------ */
  defineExpose({
    resetForm, // 暴露重置表单方法给父组件
    postFormData, // 暴露表单数据，父组件可直接修改（如编辑时回显数据）
    getDataInfo, // 暴露表单数据，父组件可直接修改（如编辑时回显数据）
    getFormParams, // 暴露获取表单参数方法
  });
</script>
<style lang="less" scoped>
  .modal-content {
    padding: 0 24px; /* 给表单内容加左右内边距，避免贴边 */
  }
  .modal-footer {
    padding: 36px 24px 0;
    border-top: 1px solid #f0f0f0;
  }
</style>
